#include "libgui.h"

/*
|---------------|
|0,0            |
|               | 
|               |         
|               | 
|               | 
|               | 
|    width,hight|
|---------------|
*/




static inline uint16_t bswap_16(uint16_t a) 
{
	return ((a >> 8) & 0xFF) | ((a << 8) & 0xFF00);
}



void LCD_DrawPoint(struct window_t *window, int16_t x,int16_t y,uint16_t color)
{
    if(NULL == window){
        draw_pixel(x,y,(color));//bswap_16
        return ;
    }

    extern void draw_pixel(uint16_t x,uint16_t y,uint16_t color);
    uint16_t pixel_x = window->x + x;
    uint16_t pixel_y = window->y + y;
    
    if(pixel_x  < (window->x )) return;
    if(pixel_y  < (window->y )) return;
    if(pixel_x  > (window->x +window->w)) return;
    if(pixel_y  > (window->y +window->h)) return;
    
    if(pixel_x < 0) return;
    if(pixel_y < 0) return;
    if(pixel_x > WIDTH-1) return;
    if(pixel_y > HIGHT-1) return;

	draw_pixel(pixel_x,pixel_y,(color));//bswap_16
} 







void LCD_DrawLine2(struct window_t *window, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t c )
{
   uint16_t n, dx, dy, sgndx, sgndy, dxabs, dyabs, x, y, drawx, drawy;

   if ( x2 < x1 )
   {
      n = x2;
      x2 = x1;
      x1 = n;
   }
   if ( y2 < y1 )
   {
      n = y2;
      y2 = y1;
      y1 = n;
   }


   dx = x2 - x1;
   dy = y2 - y1;
   dxabs = (dx>0)?dx:-dx;
   dyabs = (dy>0)?dy:-dy;
   sgndx = (dx>0)?1:-1;
   sgndy = (dy>0)?1:-1;
   x = dyabs >> 1;
   y = dxabs >> 1;
   drawx = x1;
   drawy = y1;

   //gui->pset(drawx, drawy,c);
   LCD_DrawPoint(window,drawx, drawy,c);

   if( dxabs >= dyabs )
   {
      for( n=0; n<dxabs; n++ )
      {
         y += dyabs;
         if( y >= dxabs )
         {
            y -= dxabs;
            drawy += sgndy;
         }
         drawx += sgndx;
         //gui->pset(drawx, drawy,c);
         LCD_DrawPoint(window,drawx, drawy,c);
      }
   }
   else
   {
      for( n=0; n<dyabs; n++ )
      {
         x += dxabs;
         if( x >= dyabs )
         {
            x -= dyabs;
            drawx += sgndx;
         }
         drawy += sgndy;
         //gui->pset(drawx, drawy,c);
         LCD_DrawPoint(window,drawx, drawy,c);
      }
   }
}

void LCD_DrawLine(struct window_t *window, int16_t x1,int16_t y1,int16_t x2,int16_t y2,uint16_t color)
{
	uint16_t t;
	int xerr=0,yerr=0,delta_x,delta_y,distance;
	int incx,incy,uRow,uCol;
	delta_x=x2-x1; //计算坐标增量 
	delta_y=y2-y1;
	uRow=x1;//画线起点坐标
	uCol=y1;
	if(delta_x>0)incx=1; //设置单步方向 
	else if (delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;}
	if(delta_y>0)incy=1;
	else if (delta_y==0)incy=0;//水平线 
	else {incy=-1;delta_y=-delta_y;}
	if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y;
	for(t=0;t<distance+1;t++)
	{
		LCD_DrawPoint(window,uRow,uCol,color);//画点
		xerr+=delta_x;
		yerr+=delta_y;
		if(xerr>distance)
		{
			xerr-=distance;
			uRow+=incx;
		}
		if(yerr>distance)
		{
			yerr-=distance;
			uCol+=incy;
		}
	}
}


void LCD_DrawBLine(struct window_t *window, int16_t x1, int16_t y1, int16_t x2, int16_t y2,uint8_t size,uint16_t color)
{
	uint16_t t; 
	uint16_t xerr=0,yerr=0,delta_x,delta_y,distance; 
	uint16_t incx,incy,uRow,uCol; 
	if(x1<size|| x2<size||y1<size|| y2<size)return;
	delta_x=x2-x1; //计算坐标增量 
	delta_y=y2-y1; 
	uRow=x1; 
	uCol=y1; 
	if(delta_x>0)incx=1; //设置单步方向 
	else if(delta_x==0)incx=0;//垂直线 
	else {incx=-1;delta_x=-delta_x;} 
	if(delta_y>0)incy=1; 
	else if(delta_y==0)incy=0;//水平线 
	else{incy=-1;delta_y=-delta_y;}
	if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴 
	else distance=delta_y; 
	for(t=0;t<=distance+1;t++ )//画线输出 
	{  
		LCD_DrawFillCircle(window,uRow,uCol,size,color);//画点 
		xerr+=delta_x ; 
		yerr+=delta_y ; 
		if(xerr>distance){xerr-=distance;uRow+=incx;}
		if(yerr>distance){yerr-=distance;uCol+=incy;}
	}  
} 



void LCD_DrawAngleLine(struct window_t *window, int16_t x,int16_t y,uint16_t Angle,uint16_t r,uint16_t color)
{
    double pi = 3.1415926535897932384626433832795;
	int sx=x-r;
	int sy=y-r;
	int x1,y1;  
	uint16_t r1; 
	r1=r/2+3;
	x1=sx+r+r1*sin((pi/180)*Angle); 
	y1=sy+r-r1*cos((pi/180)*Angle); 
	LCD_DrawLine(window,x,y,x1,y1,color);
}
void LCD_DrawMesh(struct window_t *window, int16_t x1, int16_t y1, int16_t x2, int16_t y2,uint16_t color)
{
   int16_t n,m;

   if ( x2 < x1 )
   {
      n = x2;
      x2 = x1;
      x1 = n;
   }
   if ( y2 < y1 )
   {
      n = y2;
      y2 = y1;
      y1 = n;
   }

   for( m=y1; m<=y2; m+=4 )
   {
      for( n=x1; n<=x2; n+=4 )
      {
         //gui->pset(n,m,c);
         // draw_pixel(n, m,color);
          LCD_DrawPoint(window,n, m,color);
      }
   }
}

void LCD_DrawRectangle(struct window_t *window, int16_t x1, int16_t y1, int16_t x2, int16_t y2,uint16_t color)
{
	LCD_DrawLine(window,x1,y1,x2,y1,color);
	LCD_DrawLine(window,x1,y1,x1,y2,color);
	LCD_DrawLine(window,x1,y2,x2,y2,color);
	LCD_DrawLine(window,x2,y1,x2,y2,color);
}






void LCD_DrawFillRectangle(struct window_t *window, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t c )
{
   int16_t n,m;

   if ( x2 < x1 )
   {
      n = x2;
      x2 = x1;
      x1 = n;
   }
   if ( y2 < y1 )
   {
      n = y2;
      y2 = y1;
      y1 = n;
   }


   for( m=y1; m<=y2; m++ )
   {
      for( n=x1; n<=x2; n++ )
      {
          LCD_DrawPoint(window,n, m,c);
      }
   }
}


void LCD_Fill(int16_t xsta,int16_t ysta,int16_t xend,int16_t yend,uint16_t color)
{          
	uint16_t i,j;
	//LCD_Address_Set(xsta,ysta,xend-1,yend-1); 
	
	for(i=ysta;i<yend;i++){
		for(j=xsta;j<xend;j++){
            //LCD_DrawPoint(i,j,color);
			//LCD_WR_DATA(color);
		}
	} 					  	    
}



void LCD_DrawCircle(struct window_t *window, int16_t x0,int16_t y0,uint16_t r,uint16_t color)
{
	int a,b;
	a=0;b=r;	  
	while(a<=b)
	{
		LCD_DrawPoint(window,x0-b,y0-a,color);             //3           
		LCD_DrawPoint(window,x0+b,y0-a,color);             //0           
		LCD_DrawPoint(window,x0-a,y0+b,color);             //1                
		LCD_DrawPoint(window,x0-a,y0-b,color);             //2             
		LCD_DrawPoint(window,x0+b,y0+a,color);             //4               
		LCD_DrawPoint(window,x0+a,y0-b,color);             //5
		LCD_DrawPoint(window,x0+a,y0+b,color);             //6 
		LCD_DrawPoint(window,x0-b,y0+a,color);             //7
		a++;
		if((a*a+b*b)>(r*r))//判断要画的点是否过远
		{
			b--;
		}
	}
}




void LCD_DrawArc1(struct window_t *window, int x,int y,int startAngle ,int endAngle ,uint16_t r,uint16_t c)
{
    //https://blog.csdn.net/li348858320/article/details/119578005
    float rad,x_tp,y_tp,i;
    i=startAngle;
    for(;i<endAngle;i=i+0.2)//此处写0.2是为了提高精度 不然半径过大有时会有虚线
    {    
        rad=0.01745*i;
        x_tp=r*cos(rad)+x;
        y_tp=-r*sin(rad)+y;        
        LCD_DrawPoint(window,(uint16_t)x_tp,(uint16_t)y_tp,c);    
    }
}
/*
void LCD_DrawCircle_jhinlfhu(uint16_t x0,uint16_t y0,uint16_t r,uint16_t r2,uint16_t color)
{
	int a,b;
	a=0;b=r;	  
	while(a<=b)
	{
		LCD_DrawFillCircle(x0-b,y0-a,r2,color);             //3           
		LCD_DrawFillCircle(x0+b,y0-a,r2,color);             //0           
		LCD_DrawFillCircle(x0-a,y0+b,r2,color);             //1                
		LCD_DrawFillCircle(x0-a,y0-b,r2,color);             //2             
		LCD_DrawFillCircle(x0+b,y0+a,r2,color);             //4               
		LCD_DrawFillCircle(x0+a,y0-b,r2,color);             //5
		LCD_DrawFillCircle(x0+a,y0+b,r2,color);             //6 
		LCD_DrawFillCircle(x0-b,y0+a,r2,color);             //7
        
		a++;
		if((a*a+b*b)>(r*r))//判断要画的点是否过远
		{
			b--;
		}
	}
}
*/


void LCD_DrawFillCircle(struct window_t *window, int16_t x0,int16_t y0,uint16_t r,uint16_t color)
{
	uint16_t x,y;
	for(y=y0 - r;y<y0 +r;y++)
	{
		for(x=x0 - r;x<x0+r;x++)
		{
			if(((x-x0)*(x-x0)+(y-y0)*(y-y0)) <= r*r)
			{
				LCD_DrawPoint(window,x,y,color);
			}
		}
	}
}

void LCD_DrawFillCircle2(struct window_t *window, int16_t x0,int16_t y0,uint16_t r,uint16_t color)
{
	int a,b;
	int di;
	a=0;b=r;	  
	di=3-(r<<1);             //判断下个点位置的标志
	while(a<=b)
	{
		int i = a,p = b;
		while(i>0){		
			LCD_DrawPoint(window,x0+b,y0-i,color);
			LCD_DrawPoint(window,x0-i,y0+b,color);
			i--;
	}		
		while(p>0){
			LCD_DrawPoint(window,x0-a,y0-p,color);
			LCD_DrawPoint(window,x0-p,y0-a,color);
			LCD_DrawPoint(window,x0+a,y0-p,color);
			LCD_DrawPoint(window,x0-p,y0+a,color);
			LCD_DrawPoint(window,x0+a,y0+p,color);
			LCD_DrawPoint(window,x0+p,y0+a,color);
			p--;
	}
		a++;
		//Bresenham算法画圆    
		if(di<0)di +=4*a+6;	  
		else
		{
			di+=10+4*(a-b);   
			b--;
		} 						    
	}
	LCD_DrawPoint(window,x0,y0,color); //圆心坐标
}


void LCD_DrawTriangle(struct window_t *window, int16_t x1,int16_t y1,int16_t x2,int16_t y2,int16_t x3,int16_t y3,uint16_t color)
{
    LCD_DrawLine(window,x1,y1,x2,y2,color);
    LCD_DrawLine(window,x2,y2,x3,y3,color);
    LCD_DrawLine(window,x1,y1,x3,y3,color);
}


#if 1
void LCD_DrawFillTriangle(struct window_t *window, int16_t x1,int16_t y1,int16_t x2,int16_t y2,int16_t x3,int16_t y3,uint16_t color)
{
	// 第一步找出XMAX  YMAX  XMIN  YMIN找出最小矩形
	int xMIN, xMAX, yMIN, yMAX;
	xMIN = (x1 < x2 ? x1 : x2) < x3 ? (x1 < x2 ? x1 : x2) : x3;
	xMAX = (x1 > x2 ? x1 : x2) > x3 ? (x1 > x2 ? x1 : x2) : x3;
	yMIN = (y1 < y2 ? y1 : y2) < y3 ? (y1 < y2 ? y1 : y2) : y3;
	yMAX = (y1 > y2 ? y1 : y2) > y3 ? (y1 > y2 ? y1 : y2) : y3;
	
	
	if (yMIN >= HIGHT)
	{
		return;
	}
	if (yMAX <= 0)
	{
		return;
	}
	if (xMIN >= WIDTH)
	{
		return;
	}
	if (xMAX <= 0)
	{
		return;
	}
 
	if (yMIN < 0)
	{
		yMIN = 0;
	}
	if (yMAX >= HIGHT)
	{
		yMAX = HIGHT - 1;
	}
	if (xMIN < 0)
	{
		xMIN = 0;
	}
	if (xMAX >= WIDTH)
	{
		xMAX = WIDTH - 1;
	}
	
	
	float signOfTrig = (x2 - x1) * (y3 - y1) - (y2 - y1) * (x3 - x1);
	float addX1 = (x2 - x1);
	float addY1 = (y2 - y1);
	float addX2 = (x3 - x2);
	float addY2 = (y3 - y2);
	float addX3 = (x1 - x3);
	float addY3 = (y1 - y3);
	float startXAB = addX1 * (yMIN - y1) - addY1 * (xMIN - x1);
	float startXCA = addX3 * (yMIN - y3) - addY3 * (xMIN - x3);
	float startXBC = addX2 * (yMIN - y2) - addY2 * (xMIN - x2);
	for (int i = xMIN; i <= xMAX; ++i)
	{
		int bStart = 0;
		float signOfAB = startXAB;
		float signOfCA = startXCA;
		float signOfBC = startXBC;
		for (int j = yMIN; j < yMAX; j++)
		{
			//PointLong p = { i, j };
			int bInTri = 0;
 
			if (signOfTrig > 0)
			{
				bInTri = (signOfAB >= 0) && (signOfCA >= 0) && (signOfBC >= 0);
			}
			else
			{
				bInTri = (signOfAB <= 0) && (signOfCA <= 0) && (signOfBC <= 0);
			}
			if (bInTri)
			{
				bStart = 1;
                LCD_DrawPoint(window,i,j,color);
				//MemSetColor(wndbuf + i + j * wndTwidth, color, 1);
			}
			else
			{
				if (bStart)
				{
					break;
				}
			}
			signOfAB += addX1;
			signOfBC += addX2;
			signOfCA += addX3;
		}
		startXAB -= addY1;
		startXBC -= addY2;
		startXCA -= addY3;
	}
}

#endif


void LCD_DrawCircle2(struct window_t *window, int16_t x0,int16_t y0,uint16_t r,uint16_t color)
{
	uint16_t i,y;
	//if((x0 < r) || (y0 < r)) return;//保证能画出完整的圆
	for(i = x0-r; i <= x0; i++){
		y = sqrt(pow(r,2)-pow((x0-i),2)); //求出在垂直坐标上的偏移
		//画左上半圆
		LCD_DrawPoint(window,i,y0-y,color);
		//画左下半圆
		LCD_DrawPoint(window,i,y0+y,color);
		//画右上半圆
		LCD_DrawPoint(window,x0*2-i,y0-y,color);
		//画右下半圆
		LCD_DrawPoint(window,x0*2-i,y0+y,color);
	}

}



void LCD_DrawChar(struct window_t *window, int16_t x,int16_t y,uint8_t word,uint16_t fc,uint16_t bc,uint16_t alpha,const struct font_t *font)
{
    //width and hight must be 8-byte aligned
    //The startbyte and endbyte must be consecutive
    
    if(font->width % 8) return;
    if(font->hight % 8) return;
    if(word > font->endbyte)return ;
    if(word < font->startbyte)return ;
    if(0 == font->ascii_code) return ;
    
    uint16_t lx=0,ly=0;//location_x
    uint16_t offset = word - font->startbyte;
    //pixel_bytes = a pixel need bytes
    uint16_t pixel_bytes = font->width * font->hight / 8;    

    for(int i=0;i<pixel_bytes;i++)
    {
        for(int j=0;j<8;j++){
            uint8_t code = *(((uint8_t *)font->ascii_code) +(pixel_bytes *offset) +i);

            if(code & (1 << j)){
                LCD_DrawPoint(window,lx+x,ly+y,fc);
            }else if(alpha){
                LCD_DrawPoint(window,lx+x,ly+y,bc);
            } 
                
            lx++;
            if(lx > (font->width-1)){lx=0;ly++;}

        }
    }

}

void LCD_DrawString(struct window_t *window, int16_t x, int16_t y, char *p, uint16_t fc, uint16_t bc,uint16_t alpha,const struct font_t *font)
{
    uint16_t newline = x;
	while(*p != 0)
	{
		LCD_DrawChar(window,x,y,*p++,fc,bc,alpha,font);
		x += font->width;
		if(*p == '\n'){
			p ++ ;
			x = newline;
			y += font->hight;
		}
	}
}

#if 1


void LCD_DrawPicture(struct window_t *window, uint16_t x,uint16_t y,uint16_t length,uint16_t width, void const *pic)
{
	uint16_t i,j;
    uint16_t *src = (void *)pic;
    
	for(i=0;i<length;i++)
        for(j=0;j<width;j++)
            LCD_DrawPoint(window,x+i,y+j,*src++);
}

#else

void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t length,uint16_t width,const uint8_t pic[])
{
	uint16_t i,j;
	uint32_t k=0;
	LCD_Address_Set(x,y,x+length-1,y+width-1);
	for(i=0;i<length;i++)
	{
		for(j=0;j<width;j++)
		{
			LCD_WR_DATA8(pic[k*2]);
			LCD_WR_DATA8(pic[k*2+1]);
			k++;
		}
	}			
}

#endif